// SPDX-License-Identifier: GPL-3.0-only
/*
 * Copyright (c) 2008-2023 100askTeam : Dongshan WEI <weidongshan@qq.com> 
 * Discourse:  https://forums.100ask.net
 */
 
/*  Copyright (C) 2008-2023 深圳百问网科技有限公司
 *  All rights reserved
 *
 * 免责声明: 百问网编写的文档, 仅供学员学习使用, 可以转发或引用(请保留作者信息),禁止用于商业用途！
 * 免责声明: 百问网编写的程序, 可以用于商业用途, 但百问网不承担任何后果！
 * 
 * 本程序遵循GPL V3协议, 请遵循协议
 * 百问网学习平台   : https://www.100ask.net
 * 百问网交流社区   : https://forums.100ask.net
 * 百问网官方B站    : https://space.bilibili.com/275908810
 * 百问网官方淘宝   : https://100ask.taobao.com
 * 联系我们(E-mail): weidongshan@qq.com
 *
 *          版权所有，盗版必究。
 *  
 * 修改历史     版本号           作者        修改内容
 *-----------------------------------------------------
 * 2024.09.20      v01         百问科技      创建文件
 *-----------------------------------------------------
 */
#include <stdio.h>
#include "mystring.h"
#include "coredump.h"
#include "coredump_interface.h"

extern int * Image$$ER_IROM1$$Base;
extern int * Image$$ER_IROM1$$Length;
extern int * Load$$ER_IROM1$$Base;
extern int * Image$$RW_IRAM1$$Base;
extern int * Image$$RW_IRAM1$$Length;
extern int * Load$$RW_IRAM1$$Base;
extern int * Image$$RW_IRAM1$$ZI$$Base;
extern int * Image$$RW_IRAM1$$ZI$$Length;	
extern uint32_t __initial_sp; 
extern uint32_t Stack_Size;  // 声明符号地址

#if 0
/* text relocate */
memcpy(&Image$$ER_IROM1$$Base, &Load$$ER_IROM1$$Base, &Image$$ER_IROM1$$Length);

/* data relocate */
memcpy(&Image$$RW_IRAM1$$Base, &Load$$RW_IRAM1$$Base, &Image$$RW_IRAM1$$Length);

/* bss clear */
memset(&Image$$RW_IRAM1$$ZI$$Base, 0, &Image$$RW_IRAM1$$ZI$$Length);
#endif

/**********************************************************************
 * 函数名称： DumpRegisters
 * 功能描述： 打印寄存器的值
 * 输入参数： sp     - hardfault.s里设置的这个参数,它是栈的地址
 *            thread - 线程名
 * 输出参数： 无
 * 返 回 值： 无
 * 修改日期        版本号     修改人	      修改内容
 * -----------------------------------------------
 * 2023/09/20	     V1.0	  韦东山	      创建
 ***********************************************************************/
static void DumpRegisters(pregs sp, char *thread)
{
	myputs("Registers@");
	myputs(thread);
	myputs("\n\r");
	myput_s_hex("R0: ", sp->r0); myputs("\n\r");
	myput_s_hex("R1: ", sp->r1); myputs("\n\r");
	myput_s_hex("R2: ", sp->r2); myputs("\n\r");
	myput_s_hex("R3: ", sp->r3); myputs("\n\r");
	myput_s_hex("R4: ", sp->r4); myputs("\n\r");
	myput_s_hex("R5: ", sp->r5); myputs("\n\r");
	myput_s_hex("R6: ", sp->r6); myputs("\n\r");
	myput_s_hex("R7: ", sp->r7); myputs("\n\r");
	myput_s_hex("R8: ", sp->r8); myputs("\n\r");
	myput_s_hex("R9: ", sp->r9); myputs("\n\r");
	myput_s_hex("R10: ", sp->r10); myputs("\n\r");
	myput_s_hex("R11: ", sp->r11); myputs("\n\r");
	myput_s_hex("R12: ", sp->r12); myputs("\n\r");
	myput_s_hex("R13(SP): ", (uint32_t)sp + sizeof(*sp)); myputs("\n\r");
	myput_s_hex("R14(LR): ", sp->lr); myputs("\n\r");
	myput_s_hex("R15(PC): ", sp->pc); myputs("\n\r");
	myput_s_hex("xPSR: ", sp->xpsr); myputs("\n\r");
}

#if !COREDUMP_IMPERFECTION_OUT
static void DumpMem(uint32_t addr, uint32_t len)
{
	uint32_t *paddr;
	uint32_t i;
	
	paddr = (uint32_t *)addr;
	myput_s_hex("mem@", addr);
	myput_s_hex(",", len);
	myputs("\n\r");
	
	for (i = 0; i < len;)
	{
		myputhex(*paddr);
		paddr++;

		i+= 4;
		if (i % 16 == 0)
			myputs("\n\r");
		else
			myputs(" ");
	}
	myputs("\n\r");
}
#endif

static void StackMem(uint32_t addr, uint32_t len, uint32_t Offset)
{
	uint32_t *paddr;
	uint32_t i;
	
	paddr = (uint32_t *)addr;
	myput_s_hex("mem@", addr);
	myput_s_hex(",", len);
	myputs("\n\r");
	
	for (i = 0; i < sizeof(regs);)
	{
		myputhex(*paddr);
		paddr++;

		i+= 4;
		if (i % 16 == 0)
			myputs("\n\r");
		else
			myputs(" ");
	}
	
	paddr = (uint32_t *)((uint8_t *)paddr + Offset);
	for (i = sizeof(regs); i < len;)
	{
		myputhex(*paddr);
		paddr++;

		i+= 4;
		if (i % 16 == 0)
			myputs("\n\r");
		else
			myputs(" ");
	}
	myputs("\n\r");
}


uint32_t ulOffset;
void DumpCore(pregs sp)
{
	
	#if COREDUMP_USE_COUNTTIME
	uint32_t ulTickStart;
	ulTickStart = __HAL_TIM_GET_COUNTER(&htim2);
	#endif
	
	#if COREDATA_SAVE
	FatFs_DeleteFile((TCHAR *)"CoreDump.txt");
	#endif 
	
	ulOffset = 0;
	// Save FPU Registers
	if((sp->exc_return & 0x10) == 0)
	{
		ulOffset = FPU_OFFSET;
		myputs("SP Save Fpu Registers, But No OutPut\n\r");
	}
	
	if((sp->xpsr & 0x200) == 0x200)
	{
		ulOffset += ALIGN_OFFSET;
		myputs("Hard Align Save Fpu Registers, But No OutPut\n\r");
	}
	
	/* 打印寄存器 */
	DumpRegisters(sp, "main_thread");
	
	myputs("Stack segment:\n\r");
	StackMem((uint32_t)sp, COREDUMP_SP_SIZE + sizeof(*sp), ulOffset);
	
	#if !COREDUMP_IMPERFECTION_OUT
	/* 打印数据段 */
	myputs("Data segment:\n\r");
	DumpMem((uint32_t)&Image$$RW_IRAM1$$Base, (uint32_t)&Image$$RW_IRAM1$$Length);

	/* 打印ZI段 */
	myputs("ZI segment:\n\r");
	DumpMem((uint32_t)&Image$$RW_IRAM1$$ZI$$Base, (uint32_t)&Image$$RW_IRAM1$$ZI$$Length);
	#endif
	
	#if COREDATA_SAVE
	FatfsBufferWrite((uint8_t *)"CoreDump.txt", (uint8_t *)0, 0, 1);
	#endif 
	
	#if COREDUMP_USE_COUNTTIME
	printf("CoreDump OutPut Time = %0.2f ms \n\r", (__HAL_TIM_GET_COUNTER(&htim2) - ulTickStart) / 10.0);
	#endif

	CoreDataOut("Enter HardFault, Input Any Reset\n\r");
	 while (1)
	 {
			uint8_t ch;
			if(HAL_UART_Receive(&huart1, &ch,1,0xFFFFFFFF) == HAL_OK)
			{
				NVIC_SystemReset();
			}
	 };
}

